#![allow(unused)]

use std::ops::RangeInclusive;

use crate::{Date, Day, February, January, Year, 年, 月份};

def_enum! {
    enum 節氣(u8) {
        小寒 =  1, 大寒 =  2, 立春 =  3, 雨水 =  4, 驚蟄 =  5, 春分 =  6,
        清明 =  7, 穀雨 =  8, 立夏 =  9, 小滿 = 10, 芒種 = 11, 夏至 = 12,
        小暑 = 13, 大暑 = 14, 立秋 = 15, 處暑 = 16, 白露 = 17, 秋分 = 18,
        寒露 = 19, 霜降 = 20, 立冬 = 21, 小雪 = 22, 大雪 = 23, 冬至 = 0 | 24,
    }
}

impl_add_sub_modulo!(節氣, 24, (u8, i8), (u16, i16), (u32, i32), (usize, isize));

struct 儒月日數 {
    數: f64,
}

const fn 儒(數: f64) -> 儒月日數 {
    儒月日數 { 數 }
}

#[rustfmt::skip]
const 節氣時間表: [儒月日數; 24] = [
    // 小寒              大寒                立春                 雨水                驚蟄                春分
    儒(       0.00), 儒( 1272494.40), 儒( 2548020.60), 儒( 3830143.80), 儒( 5120226.60), 儒( 6420865.80),
    // 清明              穀雨                立夏                 小滿                芒種                夏至
    儒( 7732018.80), 儒( 9055272.60), 儒(10388958.00), 儒(11733065.40), 儒(13084292.40), 儒(14441592.00),
    // 小暑              大暑                立秋                 處暑                白露                秋分
    儒(15800560.80), 儒(17159347.20), 儒(18513766.20), 儒(19862002.20), 儒(21201005.40), 儒(22529659.80),
    // 寒露              霜降                立冬                 小雪                大雪                冬至
    儒(23846845.20), 儒(25152606.00), 儒(26447687.40), 儒(27733451.40), 儒(29011921.20), 儒(30285477.60),
];

/// 已知1900年小寒時刻为1月6日02:05:00
const 一九〇〇年小寒: 儒月日數 = 儒(2415025.5868055555);
const 一九〇〇年: u16 = 1900;

const 回歸年日數: f64 = 365.24219878;
const 年時數: f64 = 84600.0;

impl 儒月日數 {
    fn 自年份節氣(年: u16, 節氣: 節氣) -> 儒月日數 {
        儒(一九〇〇年小寒.數
            + 回歸年日數 * (年 - 一九〇〇年) as f64
            + 節氣時間表[節氣.repr() as usize - 1].數 / 年時數)
    }
}

const 節氣計算數: usize = 25;
const 朔日計算數: usize = 15;

fn 計算自某年起連續節氣(mut 年: u16, 節氣: 節氣) -> [儒月日數; 節氣計算數] {
    std::array::from_fn(|節氣序| {
        let 節氣 = 節氣 + 節氣序;
        if 節氣 == 冬至 {
            年 += 1;
        }
        儒月日數::自年份節氣(年, 節氣)
    })
}

/// u16中第15-3位用來分別表示1-13月(含閏月)是否爲大月(1爲大月有30天；0爲小月有29天).
const 大月年表: [u16; 200] = [
    0x4AE0, 0xA570, 0x5268, 0xD260, 0xD950, 0x6AA8, 0x56A0, 0x9AD0, 0x4AE8, 0x4AE0, // 1910
    0xA4D8, 0xA4D0, 0xD250, 0xD528, 0xB540, 0xD6A0, 0x96D0, 0x95B0, 0x49B8, 0x4970, // 1920
    0xA4B0, 0xB258, 0x6A50, 0x6D40, 0xADA8, 0x2B60, 0x9570, 0x4978, 0x4970, 0x64B0, // 1930
    0xD4A0, 0xEA50, 0x6D48, 0x5AD0, 0x2B60, 0x9370, 0x92E0, 0xC968, 0xC950, 0xD4A0, // 1940
    0xDA50, 0xB550, 0x56A0, 0xAAD8, 0x25D0, 0x92D0, 0xC958, 0xA950, 0xB4A8, 0x6CA0, // 1950
    0xB550, 0x55A8, 0x4DA0, 0xA5B0, 0x52B8, 0x52B0, 0xA950, 0xE950, 0x6AA0, 0xAD50, // 1960
    0xAB50, 0x4B60, 0xA570, 0xA570, 0x5260, 0xE930, 0xD950, 0x5AA8, 0x56A0, 0x96D0, // 1970
    0x4AE8, 0x4AD0, 0xA4D0, 0xD268, 0xD250, 0xD528, 0xB540, 0xB6A0, 0x96D0, 0x95B0, // 1980
    0x49B0, 0xA4B8, 0xA4B0, 0xB258, 0x6A50, 0x6D40, 0xADA0, 0xAB60, 0x9570, 0x4978, // 1990
    0x4970, 0x64B0, 0x6A50, 0xEA50, 0x6B28, 0x5AC0, 0xAB60, 0x9368, 0x92E0, 0xC960, // 2000
    0xD4A8, 0xD4A0, 0xDA50, 0x5AA8, 0x56A0, 0xAAD8, 0x25D0, 0x92D0, 0xC958, 0xA950, // 2010
    0xB4A0, 0xB550, 0xAD50, 0x55A8, 0x4BA0, 0xA5B0, 0x52B8, 0x52B0, 0xA930, 0x74A8, // 2020
    0x6AA0, 0xAD50, 0x4DA8, 0x4B60, 0xA570, 0xA4E0, 0xD260, 0xE930, 0xD530, 0x5AA0, // 2030
    0x6B50, 0x96D0, 0x4AE8, 0x4AD0, 0xA4D0, 0xD258, 0xD250, 0xD520, 0xDAA0, 0xB5A0, // 2040
    0x56D0, 0x4AD8, 0x49B0, 0xA4B8, 0xA4B0, 0xAA50, 0xB528, 0x6D20, 0xADA0, 0x55B0, // 2050
    0x9370, 0x4978, 0x4970, 0x64B0, 0x6A50, 0xEA50, 0x6B20, 0xAB60, 0xAAE0, 0x92E0, // 2060
    0xC970, 0xC960, 0xD4A8, 0xD4A0, 0xDA50, 0x5AA8, 0x56A0, 0xA6D0, 0x52E8, 0x52D0, // 2070
    0xA958, 0xA950, 0xB4A0, 0xB550, 0xAD50, 0x55A0, 0xA5D0, 0xA5B0, 0x52B0, 0xA938, // 2080
    0x6930, 0x7298, 0x6AA0, 0xAD50, 0x4DA8, 0x4B60, 0xA570, 0x5270, 0xD260, 0xE930, // 2090
    0xD520, 0xDAA0, 0x6B50, 0x56D0, 0x4AE0, 0xA4E8, 0xA4D0, 0xD150, 0xD928, 0xD520, // 2100
];

/// u8中第7-4位表示第一年是閏幾月，第3-0位表示第二年是閏幾月。若該年數值爲0，表示該年沒有閏月
const 閏月雙年表: [u8; 100] = [
    0x00, 0x50, 0x04, 0x00, 0x20, // 1910
    0x60, 0x05, 0x00, 0x20, 0x70, // 1920
    0x05, 0x00, 0x40, 0x02, 0x06, // 1930
    0x00, 0x50, 0x03, 0x07, 0x00, // 1940
    0x60, 0x04, 0x00, 0x20, 0x70, // 1950
    0x05, 0x00, 0x30, 0x80, 0x06, // 1960
    0x00, 0x40, 0x03, 0x07, 0x00, // 1970
    0x50, 0x04, 0x08, 0x00, 0x60, // 1980
    0x04, 0x0A, 0x00, 0x60, 0x05, // 1990
    0x00, 0x30, 0x80, 0x05, 0x00, // 2000
    0x40, 0x02, 0x07, 0x00, 0x50, // 2010
    0x04, 0x09, 0x00, 0x60, 0x04, // 2020
    0x00, 0x20, 0x60, 0x05, 0x00, // 2030
    0x30, 0xB0, 0x06, 0x00, 0x50, // 2040
    0x02, 0x07, 0x00, 0x50, 0x03, // 2050
    0x08, 0x00, 0x60, 0x04, 0x00, // 2060
    0x30, 0x70, 0x05, 0x00, 0x40, // 2070
    0x80, 0x06, 0x00, 0x40, 0x03, // 2080
    0x07, 0x00, 0x50, 0x04, 0x08, // 2090
    0x00, 0x60, 0x04, 0x00, 0x20, // 2100
];

/// 農曆年的新年比公曆年晚，該數組儲存公曆年和農曆年開始(該年第一天)的偏差量(天數)
const 春節日序年表: [u8; 200] = [
    49, 38, 28, 46, 34, 24, 43, 32, 21, 40, // 1910
    29, 48, 36, 25, 44, 33, 22, 41, 31, 50, // 1920
    38, 27, 46, 35, 23, 43, 32, 22, 40, 29, // 1930
    47, 36, 25, 44, 34, 23, 41, 30, 49, 38, // 1940
    26, 45, 35, 24, 43, 32, 21, 40, 28, 47, // 1950
    36, 26, 44, 33, 23, 42, 30, 48, 38, 27, // 1960
    45, 35, 24, 43, 32, 20, 39, 29, 47, 36, // 1970
    26, 45, 33, 22, 41, 30, 48, 37, 27, 46, // 1980
    35, 24, 43, 32, 50, 39, 28, 47, 36, 26, // 1990
    45, 34, 22, 40, 30, 49, 37, 27, 46, 35, // 2000
    23, 42, 31, 21, 39, 28, 48, 37, 25, 44, // 2010
    33, 22, 40, 30, 49, 38, 27, 46, 35, 24, // 2020
    42, 31, 21, 40, 28, 47, 36, 25, 43, 33, // 2030
    22, 41, 30, 49, 38, 27, 45, 34, 23, 42, // 2040
    31, 21, 40, 29, 47, 36, 25, 44, 32, 22, // 2050
    41, 31, 49, 38, 27, 45, 34, 23, 42, 32, // 2060
    20, 39, 28, 47, 35, 25, 44, 33, 22, 41, // 2070
    30, 49, 37, 26, 45, 35, 23, 42, 32, 21, // 2080
    39, 28, 47, 36, 25, 44, 33, 23, 40, 29, // 2090
    48, 37, 26, 45, 35, 24, 42, 31, 20, 39, // 2100
];

/// 表中所含最小與最大農曆日期(以公元日期表示)：1901-02-19 至 2101-01-28。
const 表中日期範圍: RangeInclusive<Date> = Date {
    year: Year(1901),
    month: February,
    day: Day(19),
}..=Date {
    year: Year(2101),
    month: January,
    day: Day(28),
};

const 表中年範圍: RangeInclusive<年> = 年 { 年: 1901 }..=年 { 年: 2101 };

fn 表中年序(年: u16) -> usize {
    (年 - 表中年範圍.start().年) as usize
}

pub(super) fn 某年春節日序(年: u16) -> u8 {
    春節日序年表[表中年序(年)]
}

pub(super) fn 某年某月日數(年: u16, 月序: u8) -> u8 {
    if 大月年表[表中年序(年)] & (0x8000 >> 月序) != 0 {
        30
    } else {
        29
    }
}

pub(super) fn 某年閏月(年: u16) -> Option<月份> {
    let 雙年 = 閏月雙年表[表中年序(年) / 2];

    let 月份 = if 年 % 2 != 0 {
        (雙年 & 0xF0) >> 4
    } else {
        雙年 & 0x0F
    };

    (月份 != 0).then_some(unsafe { 月份::from_repr_unchecked(月份) })
}
